package model

import (
	"config-client-v1/init/global"
	j_log "config-client-v1/init/j-log"
	"config-client-v1/utils/tools"
	"fmt"
	"github.com/goccy/go-json"
	"github.com/gorilla/websocket"
	"net/url"
	"runtime/debug"
	"strings"
	"time"
)

type OPCWSRequest struct {
	Route  string                 `json:"route"`
	TS     string                 `json:"ts"`
	Params map[string]interface{} `json:"params"`
}

type OPCWSResponse struct {
	PPEID  int         `json:"ppe_id"`
	Route  string      `json:"route"`
	Code   int         `json:"code"`
	Data   string      `json:"data"`
	Msg    string      `json:"msg"`
	Status string      `json:"status"`
	Ts     string      `json:"ts"`
	Nodes  []*OPCNodes `json:"nodes"`
}

type OPCWSAddr struct { // OPC地址
	Addr  string  `json:"addr"`
	PPEID int     `json:"ppe_id"`
	Type  string  `json:"type"`
	Value float64 `json:"value"` // 这里包含OPC中的 Boolean,Float,各种Int类型的值, True为1,False为0
}

type OPCNodes struct { // OPC节点
	ID             int     `json:"id" gorm:"column:id"`
	ProjectID      int     `json:"project_id" gorm:"column:project_id"`
	PPEID          int     `json:"ppe_id" gorm:"column:ppe_id"`
	NodeId         string  `json:"NodeId" gorm:"column:NodeId"`
	IdentifierType string  `json:"identifierType" gorm:"column:identifierType"`
	NamespaceIndex string  `json:"namespaceIndex" gorm:"column:namespaceIndex"`
	NodeClass      string  `json:"nodeClass" gorm:"column:nodeClass"`
	Status         uint8   `json:"status" gorm:"column:status"`
	CreateTime     *string `json:"create_time" gorm:"column:create_time"`
}

func (m *OPCNodes) TableName() string {
	return "opc_nodes"
}

var OPCVariablesMap map[string]*Variable

func GetOPCAddrMap() {
	OPCVariablesMap = make(map[string]*Variable)
	list := make([]*Variable, 0)
	err := DB.Model(&Variable{}).Where("code1 = ?", "58").Find(&list).Error
	if err != nil {
		j_log.LogError([]interface{}{"GetOPCAddrMap 获取OPC变量失败:", err.Error()})
		return
	}
	for _, item := range list {
		key := fmt.Sprintf("%d-%s", item.PPEID, item.OPCAddr)
		OPCVariablesMap[key] = item
	}
}

func OPCWSClientRun() {
	defer func() {
		if err := recover(); err != nil {
			j_log.LogError([]interface{}{"OPCWSClientRun panic", err})
			fmt.Println(string(debug.Stack()))
		}
		//j_log.LogInfo([]interface{}{"OPCWSClient 连接断开,3秒后重连"})
		time.Sleep(3 * time.Second)
		if global.OPCWSReconnect {
			OPCWSClientRun()
		}
	}()
	GetOPCAddrMap()
	addr := global.AppConfig.Section("opc_websocket_client").Key("addr").String()
	u := url.URL{Scheme: "ws", Host: addr, Path: ""}
	j_log.LogInfo([]interface{}{fmt.Sprintf("OPCWSClient 正在连接 %s", addr)})
	conn, _, err := websocket.DefaultDialer.Dial(u.String(), nil)
	if err != nil {
		j_log.LogError([]interface{}{"OPCWSClientRun 连接失败:", err.Error()})
		return
	}
	defer conn.Close()
	j_log.LogInfo([]interface{}{fmt.Sprintf("OPCWSClient 连接成功 %s", addr)})
	OPCWSClient = conn
	for {
		_, message, err := conn.ReadMessage()
		if err != nil {
			j_log.LogError([]interface{}{"OPCWSClientRun ReadMessage error:", err.Error()})
			return
		}
		now := tools.GetNow()
		jsonContent := string(message)
		if global.OPCWSDebug {
			j_log.LogInfo([]interface{}{fmt.Sprintf("【opc_recv】%s", jsonContent)})
		}
		_ = tools.WriteStringToLog(jsonContent, "opc_message.log", "a")

		if strings.Contains(jsonContent, "\"code\"") {
			resp := OPCWSResponse{}
			err = json.Unmarshal(message, &resp)
			if err != nil {
				j_log.LogError([]interface{}{"响应值json解析失败", err.Error()})
				continue
			}
			switch resp.Route {
			case "opcua/start":
				fallthrough
			case "opcda/start":
				if resp.Code == 1 || (resp.Code == 0 && resp.Msg == "ID正在运行中") {
					ppe, ok := RunningPPEMap.Get(resp.PPEID)
					if ok {
						ppe.RunningState = 2
						ppe.Detail = "已启动"
						ppe.OPCClientLastTime = time.Now().Unix()
					} else {
						j_log.LogInfo([]interface{}{fmt.Sprintf("Mem设备已注销, route=%s, ppe_id=%d", resp.Route, resp.PPEID)})
					}
				} else {
					j_log.LogError([]interface{}{" Client启动失败", resp.Msg})
				}
			case "opcua/stop":
				fallthrough
			case "opcda/stop":
				if resp.Code == 1 || (resp.Code == 0 && resp.Msg == "ID正在运行中") {
					ppe, ok := RunningPPEMap.Get(resp.PPEID)
					if ok {
						ppe.RunningState = 3
						ppe.Detail = "正在停止"
					} else {
						j_log.LogInfo([]interface{}{fmt.Sprintf("Mem设备已注销, route=%s, ppe_id=%d", resp.Route, resp.PPEID)})
					}
				} else {
					j_log.LogError([]interface{}{" Client停止失败", resp.Msg})
				}
			case "opcua/status":
				fallthrough
			case "opcda/status":
				if resp.Code == 1 {
					if resp.Status == "1" {
						//j_log.LogInfo([]interface{}{fmt.Sprintf("OPC Client运行中, ppe_id=%d", resp.PPEID)})
						ppe, ok := RunningPPEMap.Get(resp.PPEID)
						if ok {
							ppe.RunningState = 2
							ppe.Detail = "已启动"
							ppe.OPCClientLastTime = time.Now().Unix()
						}
					} else {
						j_log.LogInfo([]interface{}{fmt.Sprintf("OPC Client未运行, ppe_id=%d", resp.PPEID)})
						ppe, ok := RunningPPEMap.Get(resp.PPEID)
						if ok {
							ppe.RunningState = 1
							ppe.Detail = "正在启动"
						}
					}
				} else {
					j_log.LogError([]interface{}{"OPC状态查询失败", resp.Msg})
				}
			case "opcua/readnodes":
				if resp.Code == 1 {
					j_log.LogInfo([]interface{}{fmt.Sprintf("Success %s, ppe_id=%d, len(nodes)=%d", resp.Route, resp.PPEID, len(resp.Nodes))})
					if len(resp.Nodes) > 0 {
						ppe := PPE{}
						err = DB.Where("id = ?", resp.PPEID).First(&ppe).Error
						if err != nil {
							j_log.LogError([]interface{}{resp.Route, "获取PPE信息失败", err.Error()})
							continue
						}
						for _, row := range resp.Nodes {
							row.ProjectID = ppe.ProjectID
							row.PPEID = resp.PPEID
							row.Status = 1
							row.CreateTime = &now
						}
						err = DB.Create(&resp.Nodes).Error
						if err != nil {
							j_log.LogError([]interface{}{"OPC节点写入数据库失败", err.Error()})
						} else {
							j_log.LogInfo([]interface{}{fmt.Sprintf("OPC节点写入数据库成功")})
						}
					}
				} else {
					j_log.LogError([]interface{}{"OPC读取节点失败", resp.Msg})
				}
			case "opcua/write":
				fallthrough
			case "opcda/write":
				if resp.Code == 1 {
					j_log.LogInfo([]interface{}{fmt.Sprintf("Success %s, ppe_id=%d", resp.Route, resp.PPEID)})
				} else {
					j_log.LogError([]interface{}{fmt.Sprintf("Error %s, ppe_id=%d", resp.Route, resp.PPEID)})
				}
			case "opcuaserver/start":
				fallthrough
			case "opcdaserver/start":
				if resp.Code == 1 || (resp.Code == 0 && resp.Msg == "ID正在运行中") {
					ppe, ok := RunningPPEMap.Get(resp.PPEID)
					if ok {
						ppe.RunningState = 2
						ppe.Detail = "已启动"
						ppe.OPCClientLastTime = time.Now().Unix()
					} else {
						j_log.LogInfo([]interface{}{fmt.Sprintf("Mem设备已注销, route=%s, ppe_id=%d", resp.Route, resp.PPEID)})
					}
				} else {
					j_log.LogError([]interface{}{" Client启动失败", resp.Msg})
				}
			case "opcuaserver/stop":
				fallthrough
			case "opcdaserver/stop":
				if resp.Code == 1 || (resp.Code == 0 && resp.Msg == "ID正在运行中") {
					ppe, ok := RunningPPEMap.Get(resp.PPEID)
					if ok {
						ppe.RunningState = 3
						ppe.Detail = "正在停止"
					} else {
						j_log.LogInfo([]interface{}{fmt.Sprintf("Mem设备已注销, route=%s, ppe_id=%d", resp.Route, resp.PPEID)})
					}
				} else {
					j_log.LogError([]interface{}{" Client停止失败", resp.Msg})
				}
			case "opcuaserver/status":
				fallthrough
			case "opcdaserver/status":
				if resp.Code == 1 {
					if resp.Status == "1" {
						//j_log.LogInfo([]interface{}{fmt.Sprintf("OPCServer Client运行中, ppe_id=%d", resp.PPEID)})
						ppe, ok := RunningPPEMap.Get(resp.PPEID)
						if ok {
							ppe.RunningState = 2
							ppe.Detail = "已启动"
							ppe.OPCClientLastTime = time.Now().Unix()
						}
					} else {
						j_log.LogInfo([]interface{}{fmt.Sprintf("OPC DA Client未运行, ppe_id=%d", resp.PPEID)})
						ppe, ok := RunningPPEMap.Get(resp.PPEID)
						if ok {
							ppe.RunningState = 1
							ppe.Detail = "正在启动"
						}
					}
				} else {
					j_log.LogError([]interface{}{"OPC DA状态查询失败", resp.Msg})
				}
			default:
				j_log.LogError([]interface{}{"OPCWSClientRun 未知的route", jsonContent})
				continue
			}

		} else if strings.Contains(jsonContent, "\"addr\"") { // ppe_id + opc_addr 俩个字段保证唯一
			resp := OPCWSAddr{}
			err = json.Unmarshal(message, &resp)
			if err != nil {
				j_log.LogError([]interface{}{"OPC推送值json解析失败", err.Error()})
				continue
			}
			key := fmt.Sprintf("%d-%s", resp.PPEID, resp.Addr)
			v, ok := OPCVariablesMap[key]
			if !ok {
				j_log.LogWarning([]interface{}{"未知的OPC变量地址", key})
				continue
			}
			queueData := QueueValue{}
			queueData.SpecType = v.SpecType
			queueData.Addr = v.Addr
			queueData.FieldName = v.FieldName
			queueData.Value = resp.Value
			queueData.CreateTime = &now
			go VariablesMap.PushMessageToClients([]*QueueValue{
				&queueData,
			})

			ppe, ok := RunningPPEMap.Get(resp.PPEID)
			if ok {
				ppe.OPCClientLastTime = time.Now().Unix()
			} else {
				j_log.LogInfo([]interface{}{"Mem设备已注销", resp.PPEID})
			}
		} else {
			fmt.Printf("[%s~%s]【recv】 %s\n", tools.GetNow(), conn.RemoteAddr().String(), jsonContent)
			j_log.LogInfo([]interface{}{"OPCWSClientRun", "未知的json格式", jsonContent})
		}

	}
}
